package com.xiaoxi.exam.book;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

@Slf4j
public class BrowserUtil {

  public static boolean login(FirefoxDriver driver, WebDriverWait wait, String userName,
      String password, int times, String ocrUrl) {
    sleep(2000);
    WebElement userNameInput = driver.findElementById("userName");
    userNameInput.clear();
    userNameInput.sendKeys(userName);
    log.info("get username input success and set {} ...", userName);
    WebElement passwordInput = driver.findElementByXPath("//input[@tabindex='2']");
    passwordInput.sendKeys(password);
    log.info("get password input success and set {} ...", password);
    WebElement verify = driver.findElementByXPath("//input[@tabindex='3']");
    verify.sendKeys("");
    WebElement img = driver.findElementByTagName("img");
    sleep(6000);
    String src = img.getAttribute("src");
    String result = getVerifyCode(src, ocrUrl);
    verify.sendKeys(result);
    log.info("get verifycode success and set {} ...", result);
    WebElement loginBtn = driver.findElementByXPath("//input[@class='btn_login']");
    //noinspection unchecked
    wait.until(input -> loginBtn);
    loginBtn.click();
    sleep(500);
    log.info("login button clicked ...");
    try {
      WebElement alart = driver
          .findElementByXPath("//div[@class='alert alert-error alert5_color']");
      if (alart.isEnabled()) {
        if (times == 3) {
          return false;
        } else {
          times++;
          System.out.println("login failed, retrying...");
          return login(driver, wait, userName, password, times, ocrUrl);
        }
      } else {
        return true;
      }
    } catch (Exception e) {
      log.info("login success");
      return true;
    }
  }

  private static String getVerifyCode(String src, String ocrUrl) {
    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<byte[]> response = restTemplate
        .exchange(src, HttpMethod.GET, null, byte[].class);
    long timeMillis = System.currentTimeMillis();
    try {
      FileUtils.writeByteArrayToFile(
          new File("/root/validates/validate-" + timeMillis + ".jpg"),
          Objects.requireNonNull(response.getBody()));
    } catch (IOException e) {
      e.printStackTrace();
    }
    FileSystemResource resource = new FileSystemResource(
        new File("/root/validates/validate-" + timeMillis + ".jpg"));
    MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
    param.add("pic", resource);
    return restTemplate
        .postForObject(ocrUrl, param, String.class);
  }

  public static void sleep(long delay) {
    try {
      TimeUnit.MILLISECONDS.sleep(delay);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static Map<String, String> selectSchool(FirefoxDriver driver, WebDriverWait wait,
      String city, List<String> dates, List<String> schools) {
    log.info("begin to search seats, city:{}, schools:{}, dates:{}", city, schools, dates);
    WebElement citySelector = driver.findElementByXPath("//select[@id='centerProvinceCity']");
    //noinspection unchecked
    wait.until(input -> citySelector);
    Select citySelect = new Select(citySelector);
    citySelect.selectByVisibleText(city);
    log.info("city selected ...");
    WebElement dateSelector = driver.findElementByXPath("//select[@id='testDays']");
    Select dateSelect = new Select(dateSelector);
    WebElement queryBtn;
    try {
      queryBtn = driver.findElementByXPath("//*[@id='btnQuerySeat']");
    } catch (Exception e) {
      return null;
    }
    Map<String, String> result = new HashMap<>();
    dates.forEach(day -> {
      log.info("querying day {} result", day);
      dateSelect.selectByVisibleText(day);
      Actions action = new Actions(driver);
      action.moveToElement(queryBtn);
      queryBtn.click();
      log.info("date selected ...");
      sleep(2000);
      if (Objects.equals("北京", city)) {
        sleep(1000);
      }
      WebElement queryTitle = driver.findElementByXPath("//*[@id='qrySeatResult']/h4");
      if (Objects.equals(queryTitle.getText(), "考位查询结果")) {
        log.info("seats result found ...");
        WebElement schoolTable = driver
            .findElementByXPath("//table[@class='table table-bordered table-striped']/tbody");
        List<WebElement> rows = schoolTable.findElements(By.tagName("tr"));
        for (int i = 0; i < rows.size(); i++) {
//          log.info("row info is : {}", rows.get(i).getText());
          List<WebElement> tds = rows.get(i).findElements(By.tagName("td"));
          WebElement school = tds.get(1);
          if (schools.parallelStream().anyMatch(sl -> school.getText().contains(sl))) {
            WebElement bookTh = tds.get(3);
            try {
              WebElement bookBtn = bookTh.findElement(By.tagName("input"));
              result.put("school", school.getText());
              result.put("date", day);
              log.info("seat hit! date:{}, school:{}", day, school.getText());
              break;
            } catch (Exception e) {
            }

//            driver.executeScript("arguments[0].scrollIntoView(true)",
//                rows.get(i - 4 < 0 ? 0 : i - 4));
//            WebElement bookBtn2 = wait
//                .until(ExpectedConditions.presenceOfElementLocated(By.xpath(
//                    "//*[@id='qrySeatResult']/div/table/tbody/tr[" + (i + 1) + "]/td[4]/input")));
////            driver.executeScript("arguments[0].click()", bookBtn2);
////            bookBtn.click();
//            sleep(2);
//            String onclick = bookBtn2.getAttribute("onclick");
//            ((JavascriptExecutor) driver).executeScript(onclick);
//            break;
          }
        }
      }
    });
    return result;
  }

  public static void clickConfirmBtn(FirefoxDriver driver, WebDriverWait wait) {
    WebElement registerBtn = driver.findElementByXPath("//a[contains(text(),'注册考试')]");
    //noinspection unchecked
    wait.until(input -> registerBtn);
    registerBtn.click();
    log.info("register button clicked ...");
    sleep(1000);
    WebElement confirmBtn = driver
        .findElementByXPath("//a[@class='layui-layer-ico layui-layer-close layui-layer-close1']");
    confirmBtn.click();
    log.info("confirm button clicked ...");
  }
}
